import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D   # 3D 绘图支持

# ---------- 1. 参数 ----------
# 控制点 (x, y, z)
P = np.array([
    [0.0, 0.0, 2.0],
    [0.0, 1.0, 1.0],
    [1.0, 1.0, 3.0],
    [1.0, 0.0, 2.0]
])

# 对应权重
w = np.array([1.0, 0.5, 0.5, 1.0])

# 采样点数
N = 200
t_vals = np.linspace(0.0, 1.0, N)

# ---------- 2. Bernstein 基函数 ----------
def bernstein(i, t):
    """三次 Bernstein 基函数 B_{i,3}(t)"""
    coeff = [1, 3, 3, 1]          # C(3,i)
    return coeff[i] * (t ** i) * ((1 - t) ** (3 - i))

# ---------- 3. 计算有理 Bézier 曲线 ----------
curve = np.zeros((N, 3))

for idx, t in enumerate(t_vals):
    B = np.array([bernstein(i, t) for i in range(4)])   # (4,)
    Q = (B * w)[:, None] * P                            # (4,3)  齐次坐标加权
    Q_sum = Q.sum(axis=0)                               # (3,)
    W   = (B * w).sum()                                # 标量
    curve[idx] = Q_sum / W                               # 齐次除法得到三维点

# ---------- 4. 绘图 ----------
fig = plt.figure(figsize=(8, 6))
ax = fig.add_subplot(111, projection='3d')
ax.plot(curve[:, 0], curve[:, 1], curve[:, 2],
        color='royalblue', linewidth=2, label='有理三次 Bézier 曲线')

# 绘制控制多边形（帮助观察）
ax.plot(P[:, 0], P[:, 1], P[:, 2],
        'k--', linewidth=1, label='控制多边形')
ax.scatter(P[:, 0], P[:, 1], P[:, 2],
           c='red', s=50, marker='o', label='控制点')

# 轴标签与图例
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
ax.set_title('空间有理三次 Bézier 曲线示例')
ax.legend()

# 调整视角（可自行修改）
ax.view_init(elev=30, azim=-60)

plt.tight_layout()
plt.show()
